<?php

/* @(#) $Id: database.php 4 2009-02-17 22:44:07Z mo@ilaven.net $ */

abstract class DBODatabase implements IPathfinderClass, IDatabase
{
	protected static $instances = array();
	protected $refCount = 1;
	
	public $connection;
	public $name;
	public $engineName = null;
	
	protected $config;
	protected $slaveConfig;

	protected $lastAffectedRows;

	protected $tables;
	protected $tableObjects = array();

	public $moduleIdentifier;

	/* As of PHP 5.3, the following can be used: */

/*	public static function alloc()
	{
		$args = func_get_args();
		$inst = static::createInstanceArgs(null, $args);
		return $inst;
	} */

	public static function createInstance($className)
	{
		$args = func_get_args();
		array_shift($args);
		/* This is a hack to avoid having to repeat the implementation of
		 * createInstance in every descendant class. If this proves to be
		 * a horrific performance hog, then descendants will have to 
		 * duplicate the code in self::createInstanceArgs() as appropriate.
		 */
		$inst = call_user_func(array($className, 'createInstanceArgs'), $className, $args);
		return $inst;
	}

	public static function createInstanceArgs($className, $args, $key = null, $engine = null, $holder = null)
	{
		if($className === null) $className == __CLASS__;
		if(!$holder && isset($args[0]) && is_object($args[0])) $holder = $args[0];
		if(isset(self::$instances[$key]))
		{
			$inst = self::$instances[$key];
		}
		else
		{
			$reflect = new ReflectionClass($className);
			array_unshift($args, $engine); /* PersistEngine */
			array_unshift($args, $key); /* PersistKey */
			$inst = $reflect->newInstanceArgs($args);
			self::$instances[$key] = $inst;
		}
		$inst->retain($holder);
		return $inst;
	}

	public function __construct($persistKey, $persistEngine, $connection, $masterIRI, $slaveIRI = null)
	{
		$this->engineName = $connection->engineName;
		$this->connection = $connection;
		$this->config = $connection->config;
		$this->slaveConfig = $connection->slaveConfig;
		$path = parse_url($masterIRI, PHP_URL_PATH);
		if(substr($path, 0, 1) == '/') $path = substr($path, 1);
		if(substr($path, -1) == '/') $path = substr($path, 0, -1);
		$this->config['name'] = $path;
		$this->name = $path;
		if($slaveIRI)
		{
			$path = parse_url($slaveIRI, PHP_URL_PATH);
			if(substr($path, 0, 1) == '/') $path = substr($path, 1);
			if(substr($path, -1) == '/') $path = substr($path, 0, -1);
			$this->slaveConfig['name'] = $path;
		}
		$this->init();
	}
	
	public function retain($obj = null)
	{
		$this->refCount++;
		return $this;
	}

	public function release($obj = null)
	{
		$this->refCount--;
		if(!$this->refCount)
		{
			$this->dealloc();
		}
	}
	
	protected function init()
	{
	}

	
	protected function dealloc()
	{
		unset($this->connection);
		unset($this->config);
		unset($this->slaveConfig);
		unset($this->tableObjects);
		parent::dealloc();
	}

	public function getQueryLog()
	{
		return $this->connection->getQueryLog();
	}
		
	public function getIRI()
	{
		$buf = $this->config['scheme'] . '://';
		if(!empty($this->config['user'])) $buf .= $this->config['user'] . '@';
		if(empty($this->config['host']))
		{
			$buf .= 'localhost';
		}
		else
		{
			$buf .= $this->config['host'];
		}
		$buf .= '/' . $this->config['name'];
		return $buf;
	}
	
	public function __set($name, $value)
	{
		if($name == 'queryLogging')
		{
			$this->connection->queryLogging = $value;
			return;
		}
		return parent::__set($name, $value);
	}
	
	public function __get($name)
	{
		throw new Exception('Undefined or hidden property ' . get_class($this) . '::' . $name);
	}

	
}

